/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository.harvest.marc21;

import cz.mzk.oai.metadataRepository.harvest.MetadataHarvester;
import cz.mzk.oai.metadataRepository.metadata.MarcRecord;
import cz.mzk.oai.metadataRepository.metadata.MetadataFormat;
import cz.mzk.oai.metadataRepository.repository.AlephBase;
import cz.mzk.oai.metadataRepository.repository.Identifier;
import cz.mzk.oai.metadataRepository.repository.Repository;
import cz.mzk.oai.metadataRepository.repository.collections.MarcBasedCollectionSelector;
import cz.mzk.oai.metadataRepository.repository.collections.MetadataCollection;
import cz.mzk.oai.metadataRepository.repository.collections.NoCollectionFoundException;
import cz.mzk.oai.metadataRepository.repository.records.NoSuchRecordException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;

/**
 *
 * @author martin
 */
public abstract class MarcHarvester implements MetadataHarvester {

    private static final Logger logger = Logger.getLogger(MarcHarvester.class.getName());
    private static final MetadataFormat marc = MetadataFormat.marc21;
    private final Repository repository;
    protected final AlephBase alephBase;
    private final MarcBasedCollectionSelector collectionSelector;

    public MarcHarvester(Repository repository, AlephBase base) {
        this.repository = repository;
        this.alephBase = base;
        this.collectionSelector = new MarcBasedCollectionSelector(repository);
    }

    protected void addOrUpdateRecordInRepository(Identifier id, Document marcMetadataDoc) throws IOException {
        MetadataCollection recentCollection = null;
        MetadataCollection newCollection = null;
        try {
            recentCollection = repository.selectCollection(id);
        } catch (NoCollectionFoundException ex) {
            logger.log(Level.WARNING, "No collection contains item {0}", id.toString());
        }
        try {
            newCollection = selectCollection(marcMetadataDoc);
        } catch (NoCollectionFoundException ex) {
            logger.log(Level.SEVERE, "No fit collection found for item {0}", id.toString());
        }
        if (recentCollection == null) {//new item
            if (newCollection == null) {
                logger.log(Level.SEVERE, "Item {0} not found in any collection and it also isn't fit to any other collection");
            } else {//add to new collection
                newCollection.addOrUpdateRecord(id, marc, marcMetadataDoc);
            }
        } else {//item already in some collection
            updateRecordInRecentCollection(id, marc, marcMetadataDoc);
            if (newCollection == null || newCollection.getName().equals(recentCollection.getName())) {
                //just update, don't move
            } else if (recentCollection.itemsCanBeMovedFromHere()) {
                //item should be moved to new collection
                repository.moveItemBetweenCollections(id, recentCollection, newCollection);
            } else {//item would be moved but collection definition forbids it
                logger.log(Level.SEVERE, "Item {0} cannot be moved to collection {1}, recent collection {2} forbids it", new Object[]{id, newCollection.getName(), recentCollection.getName()});
            }
        }
    }

    protected void setRecordDeletedInRepository(Identifier id) throws NoSuchRecordException, IOException {
        repository.setRecordDeleted(id, marc);
    }

    private MetadataCollection selectCollection(Document marcMetadataDoc) throws NoCollectionFoundException {
        MarcRecord marcRecord = new MarcRecord(marcMetadataDoc);
        return collectionSelector.chooseCollectionOrThrowException(marcRecord, alephBase);
    }

    private void updateRecordInRecentCollection(Identifier id, MetadataFormat metadataFormat, Document marcMetadataDoc) {
        try {
            repository.updateRecord(id, marc, marcMetadataDoc);
        } catch (IOException ex) {
            Logger.getLogger(MarcHarvester.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoCollectionFoundException ex) {
            Logger.getLogger(MarcHarvester.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
